package org.longteng.security.jwtkeys;


import lombok.extern.slf4j.Slf4j;

import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * ECDSA key实体类
 * <br>基于ECC的SM2证书普遍采用256位密钥长度，加密强度等同于3072位RSA证书，远高于业界普遍采用的2048位RSA证书。
 * <br>ECDSA算法是ECC+DSA的结合体，相较于RSA数字签名算法，速度快，强度高，签名短，前景乐观.
 * <br>ECC是椭圆曲线算法，其加密算法叫ECIES，签名算法叫ECDSA。JDK 并不支持 ECC 算法，
 * 可以引入 BouncyCastle 库使用。ECC算法相当耗费资源，如果单纯使用CPU进行加密/解密，效率低下
 * <groupId>org.bouncycastle</groupId>
 *             <artifactId>bcprov-jdk15on</artifactId>
 *             <version>1.64</version>
 */
@Slf4j
public class JwtECDSAKey extends JwtKeyPair {

    /**
     * SIGNALGORITHMS
     * NONEwithECDSA	112-571	256	128	JDK/BC
     * RIPEMD160withECDSA	同上	256	160	BC
     * SHA1withECDSA	...	256	160	JDK/BC
     * SHA224withECDSA	...	256	224	BC
     * SHA256withECDSA	...	256	256	JDK/BC
     * SHA384withECDSA	...	256	384	JDK/BC
     * SHA512withECDSA	...	256	512	JDK/BC
     */
    private static final String SIGNALGORITHMS = "SHA256withECDSA";   // ECIES
    // private static final String SECP256K1 = "secp256k1";
    static final String KEY_ALGORITHM = "EC";
    /*
    并且没有对ECDSA的完全支持,BC
    ECDSA签名算法，只是在JDK1.7之后才有实现.以将使用 SHA256 消息摘要算法的 ECDSA 算法指定为SHA256withECDSA
     */
    // static final String KEY_ALGORITHM = "ECDSA";

    private String ecParamSpec;

    /**
     * 构建后要调用initBuildKey
     * @param keyId
     * @param keySize
     * @param ecParamSpec
     */
    public JwtECDSAKey(String keyId, int keySize, String ecParamSpec){
        super();
        this.keyId = keyId;
        this.keySize = keySize;
        this.ecParamSpec = ecParamSpec;
    }
    public JwtECDSAKey(ECPublicKey publicKey, ECPrivateKey privateKey){
        super();
        this.publicKey = publicKey;
        this.privateKey = privateKey;
        this.keyId = UUID.randomUUID().toString();
    }

    @Override
    public ECPrivateKey getPrivateKey() {
        return (ECPrivateKey)privateKey;
    }

    public void setPrivateKey(ECPrivateKey privateKey) {
        this.privateKey =  privateKey;
    }

    @Override
    public ECPublicKey getPublicKey() {
        return (ECPublicKey)publicKey;
    }

    public void setPublicKey(ECPublicKey publicKey) {
        this.publicKey =  publicKey;
    }

    /**
     * 返回实现的加密类型
     *
     * @return
     */
    @Override
    public String getAlgorithmName() {
        return KEY_ALGORITHM;
    }

    /**
     * 返回实现的加签名类型
     *
     * @return
     */
    @Override
    public String getAlgSignatureName() {
        return SIGNALGORITHMS;
    }

    /**
     * 生成ECDSA 的密钥对
     * @return
     */
    @Override
    public JwtKeyPair initBuildKey() throws NoSuchAlgorithmException {

        /*KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(this.keySize);  // 256
        //通过对象 KeyPairGenerator 生成密匙对 KeyPair
        KeyPair keyPair = keyPairGen.generateKeyPair();
         */
        try {
            SecureRandom sr = SecureRandom.getInstanceStrong();
            // Provider BC 并未实现NoSuchProviderException，所以去掉
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            ECGenParameterSpec ecSpec = new ECGenParameterSpec(this.ecParamSpec);    // SECP256K1
            keyPairGen.initialize(ecSpec, sr);
            KeyPair keyPair = keyPairGen.generateKeyPair();

            //通过对象 KeyPair 获取ECDSA公私钥对象ECPublicKey ECPrivateKey
            this.publicKey = (ECPublicKey) keyPair.getPublic();
            this.privateKey = (ECPrivateKey) keyPair.getPrivate();
        } catch ( InvalidAlgorithmParameterException e) {
            log.error("生成ECDSA的密钥对错误。", e);
            throw new NoSuchAlgorithmException("生成ECDSA的密钥对错误。", e);
        }
        return this;
    }

    /**
     * 公钥字符串转换成公钥
     *
     * @param pubKeyBaseStr
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    @Override
    public PublicKey reaPubKey(String pubKeyBaseStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 创建 已编码的公钥规格
        KeySpec encPubKeySpec = readPubKeySpec(pubKeyBaseStr);

        // 获取指定算法的密钥工厂, 根据 已编码的公钥规格, 生成公钥对象
        PublicKey pubKey = KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(encPubKeySpec);
        return pubKey;
    }

    /**
     * 私钥字符串转换成私钥
     *
     * @param priKeyBaseStr
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    @Override
    public PrivateKey reaPriKey(String priKeyBaseStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 创建 已编码的私钥规格
        KeySpec encPriKeySpec = readPriKeySpec(priKeyBaseStr);

        // 获取指定算法的密钥工厂, 根据 已编码的私钥规格, 生成私钥对象
        PrivateKey priKey = KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(encPriKeySpec);
        return priKey;
    }
}
